using System;
using UnityEngine;
using UnityEngine.Events;

namespace GameBaseFramework.Attribute
{
    /// <summary>
    /// 一次函数类
    /// </summary>
    public class LinearFunction
    {
        /// <summary>
        /// 斜率
        /// </summary>
        public float slope = 1.0f;
        /// <summary>
        /// 截距
        /// </summary>
        public float intercept = 0f;

        /// <summary>
        /// value1 = k * value2 + b
        /// </summary>
        /// <param name="value1"></param>
        /// <param name=""></param>
        public void Apply(ref float value1, float value2)
        {
            value1 = value2 * slope + intercept;
        }
        /// <summary>
        /// value1 = k * value2 + b
        /// </summary>
        /// <param name="value1"></param>
        /// <param name=""></param>
        public void Apply(ref int value1, int value2)
        {
            value1 = (int)(value2 * slope + intercept);
        }

        /// <summary>
        /// 设置值
        /// </summary>
        /// <param name="Slope"></param>
        /// <param name="Intercept"></param>
        public void Set(float Slope , float Intercept = 0f)
        {
            slope = Slope;
            intercept = Intercept;
        }
        
        /// <summary>
        /// 重置
        /// </summary>
        public void Reset()
        {
            slope = 1.0f;
            intercept = 0f;
        }
    }


    /// <summary>
    /// 浮点值类型
    /// 所使用的的变量均为值类型，无需继承IDispose接口
    /// UnityEvent据说有内存泄漏，也许这么多年过去了已经解决掉了
    /// </summary>
    [Serializable]
    public class FloatAttribute : IEquatable<FloatAttribute>
    {
        /// <summary>
        /// 用一次函数表示当前值和基础值之间的关系
        /// </summary>
        public LinearFunction ValueFunction = new();

        /// <summary>
        /// CurrentValue绑定的事件
        /// </summary>
        [HideInInspector]
        public UnityEvent<float, float> OnCurrentValueChange = new();

        /// <summary>
        /// 基础值
        /// </summary>
        [SerializeField]
        private float _BaseValue;
        public float BaseValue
        {
            get
            {
                return _BaseValue;
            }
            set
            {
                _BaseValue = value;
                _CurrentValue = ValueFunction.slope * _BaseValue + ValueFunction.intercept;
            }
        }

        /// <summary>
        /// 当前值
        /// </summary>
        [SerializeField]
        private float _CurrentValue;
        public float CurrentValue
        {
            get
            {
                return _CurrentValue;
            }
            set
            {
                _CurrentValue = value;
                _BaseValue = (_CurrentValue - ValueFunction.intercept) / ValueFunction.intercept;
            }
        }

        /// <summary>
        /// 构造初始化
        /// </summary>
        /// <param name="value"></param>
        public FloatAttribute(float value)
        {
            _BaseValue = value;
            _CurrentValue = value;
        }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="floatAttribute"></param>
        public FloatAttribute(FloatAttribute floatAttribute)
        {
            _BaseValue = floatAttribute.BaseValue;
            _CurrentValue = floatAttribute.CurrentValue;
        }



        /// <summary>
        /// 构造初始化
        /// </summary>
        /// <param name="value1"></param>
        /// <param name="value2"></param>
        public FloatAttribute(float value1, float value2)
        {
            _BaseValue = value1;
            _CurrentValue = value2;
        }

        /// <summary>
        /// 构造初始化
        /// </summary>
        public FloatAttribute()
        {
            _BaseValue = 0;
            _CurrentValue = 0;
        }

        /// <summary>
        /// 强制赋值而不触发属性访问器
        /// </summary>
        /// <param name="data"></param>
        /// <param name="value"></param>
        public void Set(float Base, float Current)
        {
            this._BaseValue = Base;
            this._CurrentValue = Current;
        }

        /// <summary>
        /// 强制赋值而不触发属性访问器
        /// </summary>
        /// <param name="data"></param>
        /// <param name="value"></param>
        public void Set(float Base)
        {
            this._BaseValue = Base;
        }

        #region 重写==和!=同时也要重写Equals()和GetHashCode()
        public override bool Equals(object obj)
        {
            return Equals(obj as FloatAttribute);
        }

        public bool Equals(FloatAttribute other)
        {
            return other != null &&
                   _BaseValue == other._BaseValue &&
                   BaseValue == other.BaseValue &&
                   _CurrentValue == other._CurrentValue &&
                   CurrentValue == other.CurrentValue;
        }

        public override int GetHashCode()
        {
            return HashCode.Combine(_BaseValue, BaseValue, _CurrentValue, CurrentValue);
        }


        #endregion

        /// <summary>
        /// 强转
        /// </summary>
        /// <param name="value"></param>
        public static explicit operator float(FloatAttribute value)
        {
            return value.BaseValue;
        }

        /// <summary>
        /// ==
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(FloatAttribute x, FloatAttribute y)
        {
            return x.Equals(y);
        }
        /// <summary>
        /// ==
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(FloatAttribute x, FloatAttribute y)
        {
            return !x.Equals(y);
        }

        /// <summary>
        /// ==
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(FloatAttribute x, float y)
        {
            return (x._CurrentValue == y);
        }

        /// <summary>
        /// ==
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(FloatAttribute x, float y)
        {
            return (x._CurrentValue != y);
        }
        public static bool operator >(FloatAttribute x, FloatAttribute y) => (x._CurrentValue > y._CurrentValue);
        public static bool operator <(FloatAttribute x, FloatAttribute y) => (x._CurrentValue < y._CurrentValue);
        public static FloatAttribute operator -(FloatAttribute x, FloatAttribute y)
        {
            x.BaseValue -= y.BaseValue;
            return x;
        }

        public static FloatAttribute operator +(FloatAttribute x, FloatAttribute y)
        {
            x.BaseValue += y.BaseValue;
            return x;
        }
    }
}
